﻿
Imports std
Imports lock_t = lockWrapper(Of locks.eventCombLock)

Partial Public Class node
    Partial Public Class locked_properties
        Private ReadOnly p As properties = Nothing
        Private ReadOnly l As lock_t = Nothing
        Private ReadOnly id As Int64 = 0
        Private dirty As Boolean = False
        Private destroyed As singleentry

        Public Sub New(ByVal id As Int64)
            Me.id = id
            p = New properties(id)
            l = New lock_t()
            start()
        End Sub

        Private Function locked(ByVal d As _do(Of eventComb)) As eventComb
            assert(Not d Is Nothing)
            Dim ec As eventComb = Nothing
            Return New eventComb(Function() As Boolean
                                     Return p.waitfor_initialized() AndAlso
                                            waitfor(l) AndAlso
                                            goto_next()
                                 End Function,
                                 Function() As Boolean
                                     ec = d()
                                     assert(Not ec Is Nothing)
                                     Return waitfor(ec) AndAlso
                                            goto_next()
                                 End Function,
                                 Function() As Boolean
                                     l.release()
                                     Return ec.end_result() AndAlso
                                            goto_end()
                                 End Function)
        End Function

        Private Function locked(ByVal d As _do(Of Boolean)) As eventComb
            assert(Not d Is Nothing)
            Return locked(Function() As eventComb
                              Return New eventComb(Function() As Boolean
                                                       Return d() AndAlso
                                                              goto_end()
                                                   End Function)
                          End Function)
        End Function

        Private Function unlock_get(ByVal key As String, ByRef output As iproperty) As Boolean
            If isemptystring(key) Then
                Return False
            Else
                Dim it As properties.iterator = Nothing
                it = p.find(key)
                Return it <> p.end() AndAlso eva(output, (+it).second)
            End If
        End Function

        Public Function [get](ByVal key As String, ByVal output As pointer(Of iproperty)) As eventComb
            Dim p As iproperty = Nothing
            Return locked(Function() unlock_get(key, p) AndAlso eva(output, p))
        End Function

        Private Function unlock_get(Of T)(ByVal key As String, ByRef output As T) As Boolean
            Dim p As iproperty = Nothing
            Return unlock_get(key, p) AndAlso convertor.cast(Of T)(p, output)
        End Function

        Public Function [get](Of T, PT As iproperty(Of T)) _
                             (ByVal key As String, ByVal output As pointer(Of PT)) As eventComb
            Dim p As PT = Nothing
            Return locked(Function() unlock_get(key, p) AndAlso eva(output, p))
        End Function

        Public Function [get](Of T)(ByVal key As String, ByVal output As pointer(Of iproperty(Of T))) As eventComb
            Return [get](Of T, iproperty(Of T))(key, output)
        End Function

        Private Function unlock_create_get(Of T, PT As iproperty(Of T)) _
                                          (ByVal key As String, ByRef output As iproperty(Of T)) As Boolean
            If isemptystring(key) Then
                Return False
            Else
                Dim it As properties.iterator = Nothing
                it = p.find(key)
                If it = p.end() Then
                    output = [property].create(Of PT)(id, key)
                    p(key) = output
                Else
                    output = (+it).second
                End If
                assert(Not output Is Nothing)
                Return True
            End If
        End Function

        Private Function create_get(Of T, PT As iproperty(Of T), PT2 As iproperty(Of T)) _
                                   (ByVal key As String, ByVal output As pointer(Of PT2)) As eventComb
            Dim p As iproperty(Of T) = Nothing
            Return locked(Function() unlock_create_get(Of T, PT)(key, p) AndAlso eva(output, p))
        End Function

        Public Function create_get(Of T, PT As iproperty(Of T)) _
                                  (ByVal key As String, ByVal output As pointer(Of PT)) As eventComb
            Return create_get(Of T, PT, PT)(key, output)
        End Function

        Public Function create_get(Of T, PT As iproperty(Of T)) _
                                  (ByVal key As String, ByVal output As pointer(Of iproperty(Of T))) As eventComb
            Return create_get(Of T, PT, iproperty(Of T))(key, output)
        End Function

        Private Function unlock_set(ByVal key As String, ByVal pr As iproperty) As Boolean
            If isemptystring(key) OrElse pr Is Nothing Then
                Return False
            Else
                Dim it As properties.iterator = Nothing
                it = p.find(key)
                If it <> p.end() Then
                    Return False
                Else
                    dirty = True
                    p(key) = pr
                    Return True
                End If
            End If
        End Function

        Public Function [set](ByVal key As String, ByVal pr As iproperty) As eventComb
            Return locked(Function() unlock_set(key, pr))
        End Function

        Private Function unlock_erase(ByVal key As String) As eventComb
            Return New eventComb(Function() As Boolean
                                     If isemptystring(key) Then
                                         Return False
                                     Else
                                         Dim it As properties.iterator = Nothing
                                         Dim pr As iproperty = Nothing
                                         it = p.find(key)
                                         Return it <> p.end() AndAlso
                                                eva(pr, (+it).second) AndAlso
                                                assert(Not pr Is Nothing) AndAlso
                                                p.erase(it) AndAlso
                                                eva(dirty, True) AndAlso
                                                do_(Function() As Boolean
                                                        l.release()
                                                        Return True
                                                    End Function, False) AndAlso
                                                waitfor(pr.destroy()) AndAlso
                                                goto_end()
                                     End If
                                 End Function)
        End Function

        Public Function [erase](ByVal key As String) As eventComb
            Return locked(Function() unlock_erase(key))
        End Function

        Private Function unlock_destroy() As eventComb
            Dim it As properties.iterator = Nothing
            Return New eventComb(Function() As Boolean
                                     Return assert(destroyed.mark_in_use()) AndAlso
                                            eva(it, p.begin()) AndAlso
                                            goto_next()
                                 End Function,
                                 Function() As Boolean
                                     If it = p.end() Then
                                         Return goto_end()
                                     Else
                                         Dim pr As [property] = Nothing
                                         pr = (+it).second
                                         it += 1
                                         Return waitfor(pr.destroy())
                                     End If
                                 End Function)
        End Function

        Public Sub destroy()
            assert_begin(locked(Function() unlock_destroy()))
        End Sub

        Private Function destroyed_ec_wrapper(ByVal d As _do(Of Boolean)) As _do(Of Boolean)
            assert(Not d Is Nothing)
            Return Function() As Boolean
                       If destroyed.in_use() Then
                           Return goto_end()
                       Else
                           Return d()
                       End If
                   End Function
        End Function

        Private Sub start()
            assert_begin(New eventComb(Function() As Boolean
                                           Return p.waitfor_initialized() AndAlso
                                                  goto_next()
                                       End Function,
                                       destroyed_ec_wrapper(
                                           Function() As Boolean
                                               If dirty Then
                                                   Return waitfor(l) AndAlso
                                                          goto_next()
                                               Else
                                                   Return goto_last()
                                               End If
                                           End Function),
                                       destroyed_ec_wrapper(
                                           Function() As Boolean
                                               assert(dirty)
                                               Return waitfor(p.pl.get_set_data(
                                                          Function(ByRef v As [set](Of String)) As Boolean
                                                              v.clear()
                                                              Dim it As properties.iterator = Nothing
                                                              it = p.begin()
                                                              While it <> p.end()
                                                                  v.insert((+it).first())
                                                                  it += 1
                                                              End While
                                                              dirty = False
                                                              l.release()
                                                              Return True
                                                          End Function)) AndAlso
                                                      goto_next()
                                           End Function),
                                       destroyed_ec_wrapper(
                                           Function() As Boolean
                                               Return waitfor(write_back_interval_ms) AndAlso
                                                      [goto](1)
                                           End Function)))
        End Sub
    End Class
End Class
